package com.googlecode.maratische.google.dao.impl;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.log4j.Logger;

import be.lechtitseb.google.reader.api.model.feed.FeedDescriptor;
import be.lechtitseb.google.reader.api.model.opml.Outline;

import com.googlecode.maratische.google.BaseException;
import com.googlecode.maratische.google.dao.FeedDao;
import com.googlecode.maratische.google.dao.ItemDao;
import com.googlecode.maratische.google.model.Command;
import com.googlecode.maratische.google.model.CommandUpdateFeedOffline;
import com.googlecode.maratische.google.model.Commands;
import com.googlecode.maratische.google.model.Feed;
import com.googlecode.maratische.google.model.Item;

public class FeedDaoImpl extends BaseDaoImpl<Feed> implements FeedDao {

	private ItemDao itemDao;
	
	
	protected static Logger getLogger() {
		return Logger.getLogger(FeedDaoImpl.class.getName());
	}
	
	public FeedDaoImpl(Connection conn, ItemDao itemDao) {
		super(conn);
		this.itemDao = itemDao;
	}

	/**
	 * возвращает список помеченных меток
	 * @return
	 * @throws SQLException
	 * @throws BaseException
	 */
	public List<Feed> listLabeledFeeds() throws SQLException, BaseException {
		return list("ID in (select distinct FEED_ID from ITEM where LABEL_ID is not NULL)", null);
	}
	
	public List<Feed> findByParentId(Integer parentId) throws SQLException, BaseException {
		return list("PARENT_ID = ?", "NAME", new Object[] {parentId});
	}

	public List<Feed> findByNameAndXMLUrl(String name, String xmlurl) throws SQLException, BaseException {
		return list("NAME = ? and XMLURL = ?", null, new Object[] {name, xmlurl});
	}

	public List<Feed> findByXMLUrl(String xmlurl) throws SQLException, BaseException {
		return list("XMLURL = ?", null, new Object[] {xmlurl});
	}
	
	public Feed findByFeedDescriptorId(String feedDescriptorId) throws SQLException, BaseException {
		List<Feed> list = list("FEED_DESCRIPTOR_ID = ?", null, new Object[] {feedDescriptorId});
		if (list != null && list.size()>0) {
			return list.get(0);
		}
		return null;
	}
	
	
	@Override
	protected String getTableName() {
		return "FEED";
	}

	public List<Command> saveAndUpdateOutline(Outline outline, List<FeedDescriptor> feedsUnread, List<FeedDescriptor> feedsAll, Integer parentId) {
		List<Command> commands = new ArrayList<Command>();
		Feed feed = new Feed();
		feed.setOfflineSupport(null);
//		feed.setUnreadItems(0);
		int unreadItems = 0;
		feed.setParentId(parentId);
		feed.setFeedDescriptorId("");//может быть нельзя быть ему пустым?
		if (outline.getXmlUrl() != null) {
			feed.setXmlUrl(outline.getXmlUrl());
		} else {
			feed.setXmlUrl("");
		}
		feed.setName(outline.getTitle());//empty Name for null values
		for (FeedDescriptor feedDescriptor : feedsUnread) {
			String searchId = feedDescriptor.getId().substring(5);
			if (searchId.equals(outline.getXmlUrl())) {
				unreadItems = feedDescriptor.getUnreadItems();
				feed.setUnreadItems(feedDescriptor.getUnreadItems());
				feed.setFeedDescriptorId(feedDescriptor.getId());
				break;
			}
		}
		//для вариантов, когда нет данного feed в списке не прочитанных
		if (feed.getFeedDescriptorId().equals("")) {
			for (FeedDescriptor feedDescriptor : feedsAll) {
				String searchId = feedDescriptor.getId().substring(5);
				if (searchId.equals(outline.getXmlUrl())) {
					feed.setUnreadItems(0);
					feed.setFeedDescriptorId(feedDescriptor.getId());
					break;
				}
			}
		}
		try {
			List<Feed> searchedFeeds = this.findByNameAndXMLUrl(feed.getName(), feed.getXmlUrl());
			if (searchedFeeds != null && searchedFeeds.size()>0) {
				feed.setId(searchedFeeds.get(0).getId());
				feed.setOfflineSupport(searchedFeeds.get(0).getOfflineSupport());
				feed.setUnreadItems(searchedFeeds.get(0).getUnreadItems());
//				unreadItems = searchedFeeds.get(0).getUnreadItems();
				//если FeedDescriptorId пустой, а в базе он есть = обновить его
				//возникает когда в базе есть не прочитанные, а при текущем заборе они не пришли
				if (feed.getFeedDescriptorId().equals("")
						&& !searchedFeeds.get(0).getFeedDescriptorId().equals("")) {
					feed.setFeedDescriptorId(searchedFeeds.get(0).getFeedDescriptorId());
				}
			}
			if (unreadItems>0) {
				feed.setUnreadItems(unreadItems);
			}
			/**
			 * TODO надо сверять Feed и если одинаковые, то не сохранять!
			 */
			feed = this.save(feed);
//			feed.setUnreadItems();
//			logger.debug("feed " + feed.getName()+" xml:"+feed.getXmlUrl()+"\n"+feed.getUnreadItems()+" "+feed.getOfflineSupport()+"\n"+feed.getFeedDescriptorId());
			if (feed.getOfflineSupport() != null && feed.getOfflineSupport().booleanValue()
					&& feed.getFeedDescriptorId() != null && feed.getFeedDescriptorId().length()>0
					&& (unreadItems>0 || feed.getUnreadItems()>0)) {
				CommandUpdateFeedOffline command = (CommandUpdateFeedOffline)Command.createCommand(Commands.UpdateFeedOffline);
				command.setString1(feed.getFeedDescriptorId());
				commands.add(command);
			}
			//work with childs
			if (outline.getChilds() != null && outline.getChilds().size()>0) {
				for (Outline outline2 : outline.getChilds()) {
					commands.addAll(saveAndUpdateOutline(outline2, feedsUnread, feedsAll, feed.getId()));
				}
			}

		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (BaseException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return commands;
	}
	
	Map<String, Integer> unreadItemsMap = new HashMap<String, Integer>();
	
	@Override
	public Feed createByRow(ResultSet rs) throws SQLException, BaseException {
		Feed feed =new Feed();
		feed.setId(rs.getInt("ID"));
		feed.setParentId(rs.getInt("PARENT_ID"));
		feed.setName(rs.getString("NAME"));
		feed.setXmlUrl(rs.getString("XMLURL"));
		int offlineSupport = rs.getInt("OFFLINE_SUPPORT");
		if (offlineSupport == -1) {
			feed.setOfflineSupport(null);
		} else {
			feed.setOfflineSupport(offlineSupport == 1);
		}
		feed.setUnreadItems(0);
//		feed.setUnreadItems(rs.getInt("UNREAD_ITEMS"));
		feed.setFeedDescriptorId(rs.getString("FEED_DESCRIPTOR_ID"));
		/**
		 * TODO заменить на вьюху
		 */
		if (feed.getOfflineSupport() != null && feed.getOfflineSupport() && this.itemDao != null) {
			feed.setUnreadItems(this.itemDao.countItemsByFeedIdUnread(feed.getId()));
		} else if ((feed.getOfflineSupport() == null || !feed.getOfflineSupport()) && unreadItemsMap.get(feed.getFeedDescriptorId())!= null) {
			feed.setUnreadItems(unreadItemsMap.get(feed.getFeedDescriptorId()));
		}
		return feed;
	}

	@Override
	protected String generateInsertSql() {
		return "insert into "+getTableName()+" (NAME,XMLURL,PARENT_ID, OFFLINE_SUPPORT, FEED_DESCRIPTOR_ID) values (?,?,?,?,?)";
	}

	@Override
	protected String generateUpdateSql() {
		return "update "+getTableName()+" set NAME = ?,XMLURL = ?,PARENT_ID = ?, OFFLINE_SUPPORT = ?, FEED_DESCRIPTOR_ID = ? "+
		" where ID = ? ";
	}

	@Override
	protected PreparedStatement putInsertPrepareStatement(PreparedStatement pStat, Feed status) throws SQLException {
		pStat.setString(1, status.getName());
		pStat.setString(2, status.getXmlUrl());
		pStat.setInt(3, status.getParentId());
		if (status.getOfflineSupport() == null) {
			pStat.setInt(4, -1);
		} else {
			pStat.setBoolean(4, status.getOfflineSupport());
		}
		pStat.setString(5, status.getFeedDescriptorId());
		if (status.getOfflineSupport() == null || !status.getOfflineSupport()) {
			unreadItemsMap.put(status.getFeedDescriptorId(),status.getUnreadItems());
		}
		return pStat;
	}
	
	@Override
	protected PreparedStatement putUpdatePrepareStatement(PreparedStatement pStat, Feed status) throws SQLException {
		pStat = putInsertPrepareStatement(pStat, status);
		pStat.setInt(6, status.getId());
		return pStat;
	}

}
